﻿///////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2023, ООО 1С-Софт
// Все права защищены. Эта программа и сопроводительные материалы предоставляются 
// в соответствии с условиями лицензии Attribution 4.0 International (CC BY 4.0)
// Текст лицензии доступен по ссылке:
// https://creativecommons.org/licenses/by/4.0/legalcode
///////////////////////////////////////////////////////////////////////////////////////////////////////

#Если Сервер Или ТолстыйКлиентОбычноеПриложение Или ВнешнееСоединение Тогда

#Область ОбработчикиСобытий

Процедура ОбработкаПолученияФормы(ВидФормы, Параметры, ВыбраннаяФорма, ДополнительнаяИнформация, СтандартнаяОбработка)
	
	#Если Сервер Или ТолстыйКлиентОбычноеПриложение Или ВнешнееСоединение Тогда
		
	Если Параметры <> Неопределено И Параметры.Свойство("ОткрытаПоСценарию") Тогда
		СтандартнаяОбработка = Ложь;
		ВидИнформации = Параметры.ВидКонтактнойИнформации;
		ВыбраннаяФорма = ИмяФормыВводаКонтактнойИнформации(ВидИнформации);
	
		Если ВыбраннаяФорма = Неопределено Тогда
			ТекстСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Не обрабатываемый тип адреса: ""%1""'"), ВидИнформации);
			ВызватьИсключение ТекстСообщения;
		КонецЕсли;
		
	КонецЕсли;
	
	#КонецЕсли
	
КонецПроцедуры

#КонецОбласти

#Область СлужебныйПрограммныйИнтерфейс

Функция ДоступныДополнительныеНастройкиАдреса() Экспорт
	Возврат Метаданные.Обработки.РасширенныйВводКонтактнойИнформации.Формы.Найти("НастройкиАдреса") <> Неопределено;
КонецФункции

#КонецОбласти

#Область СлужебныеПроцедурыИФункции

// Возвращает имя формы для редактирования типа контактной информации.
//
// Параметры:
//      ВидИнформации - ПеречислениеСсылка.ТипыКонтактнойИнформации
//                    - СправочникСсылка.ВидыКонтактнойИнформации -
//                      запрашиваемый тип.
//
// Возвращаемое значение:
//      Строка - полное имя формы.
//
Функция ИмяФормыВводаКонтактнойИнформации(Знач ВидИнформации)
	
	ТипИнформации = УправлениеКонтактнойИнформациейСлужебныйПовтИсп.ТипВидаКонтактнойИнформации(ВидИнформации);
	
	ВсеТипы = "Перечисление.ТипыКонтактнойИнформации.";
	Если ТипИнформации = ПредопределенноеЗначение(ВсеТипы + "Адрес") Тогда
		Возврат "Обработка.ВводКонтактнойИнформации.Форма.ВводАдреса";
		
	ИначеЕсли ТипИнформации = ПредопределенноеЗначение(ВсеТипы + "Телефон") Тогда
		Возврат "Обработка.ВводКонтактнойИнформации.Форма.ВводТелефона";
		
	ИначеЕсли ТипИнформации = ПредопределенноеЗначение(ВсеТипы + "Факс") Тогда
		Возврат "Обработка.ВводКонтактнойИнформации.Форма.ВводТелефона";
		
	КонецЕсли;
	
	Возврат Неопределено;
	
КонецФункции

#Область ВзаимодействиеСАдреснымКлассификатором

// Возвращает флаг того, что текущий пользователь может загружать или очищать адресный классификатор.
//
// Возвращаемое значение:
//     Булево- результат проверки.
//
Функция ЕстьВозможностьИзмененияАдресногоКлассификатора() Экспорт
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.АдресныйКлассификатор") Тогда
		ОбъектКонтроля = Метаданные.РегистрыСведений.Найти("АдресныеОбъекты");
		Возврат ОбъектКонтроля <> Неопределено И ПравоДоступа("Изменение", ОбъектКонтроля) И НЕ ОбщегоНазначения.РазделениеВключено();
	КонецЕсли;
	
	Возврат Ложь;
	
КонецФункции

// Проверка доступности поставщика - локальной базы или сервиса. Запрос версии.
// 
// Возвращаемое значение:
//     Структура:
//       * Отказ                        - Булево - поставщик не доступен.
//       * ПодробноеПредставлениеОшибки - Строка - описание ошибки, если поставщик недоступен. Неопределено, если Отказ
//                                                 = Ложь.
//       * КраткоеПредставлениеОшибки   - Строка - описание ошибки, если поставщик недоступен. Неопределено, если Отказ
//                                                 = Ложь.
//       * Данные                       - Строка - описание версии поставщика.
//
Функция ВерсияПоставщикаДанныхКлассификатора()
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.АдресныйКлассификатор") Тогда
		МодульАдресныйКлассификаторСлужебный = ОбщегоНазначения.ОбщийМодуль("АдресныйКлассификаторСлужебный");
		Возврат МодульАдресныйКлассификаторСлужебный.ВерсияПоставщикаДанных();
	КонецЕсли;
	
	Результат = СтруктураОшибкиПоставщикаАдресногоКлассификатора();
	Результат.Вставить("Версия");
	Возврат Результат;
	
КонецФункции

// Проверяет доступность классификатора и помещает результат в хранилище
//
Процедура ПроверитьДоступностьКлассификатора(ДоступностьКлассификатораАдрес, АдресРезультата) Экспорт
	
	ПоместитьВоВременноеХранилище(ВерсияПоставщикаДанныхКлассификатора(), АдресРезультата);
	
КонецПроцедуры

// Возвращает наименование региона по его коду.
//
//  Параметры:
//      Код - Строка
//          - Число - код региона.
//
// Возвращаемое значение:
//      Строка - полное наименование региона с сокращением.
//      Неопределено - если нет ни одной подсистемы адресного классификатора.
// 
Функция РегионКода(Знач Код)
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.АдресныйКлассификатор") Тогда
		МодульАдресныйКлассификатор = ОбщегоНазначения.ОбщийМодуль("АдресныйКлассификатор");
		Возврат МодульАдресныйКлассификатор.НаименованиеРегионаПоКоду(Код);
	КонецЕсли;
	
	Возврат Неопределено;
	
КонецФункции

// Возвращаемое значение:
//  Структура:
//   * КодСтраны - Строка
//   * КодГорода - Строка
//   * НомерТелефона - Строка
//
Функция ПодсказкиПриВводеТелефона() Экспорт
	
	Подсказки = Новый Структура(); 
	Подсказки.Вставить("КодСтраны", "+7");
	Подсказки.Вставить("КодГорода", "495");
	Подсказки.Вставить("НомерТелефона", "123-45-56");
	
	Возврат Подсказки;
	
КонецФункции

// Возвращает структуру, описывающую населенный пункт в иерархии младший-старший
//  для текущего адресного классификатора. Имена ключей структуры зависят от 
//  классификатора.
//
//  Параметры:
//      СведенияОбАдресномОбъекте - Структура
//
// Возвращаемое значение:
//      Структура - описание населенного пункта.
//
Функция СписокРеквизитовНаселенныйПункт(СведенияОбАдресномОбъекте) Экспорт
	
	Адрес = УправлениеКонтактнойИнформацией.ОписаниеНовойКонтактнойИнформации(Перечисления.ТипыКонтактнойИнформации.Адрес);
	
	Если СведенияОбАдресномОбъекте = Неопределено Тогда
		Возврат Адрес;
	КонецЕсли;
	
	Если Не ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.АдресныйКлассификатор") Тогда
		Возврат Неопределено;
	КонецЕсли;
	
	МодульАдресныйКлассификаторСлужебный = ОбщегоНазначения.ОбщийМодуль("АдресныйКлассификаторСлужебный");
	АдресныеСведения = МодульАдресныйКлассификаторСлужебный.АктуальныеАдресныеСведения(СведенияОбАдресномОбъекте);
	
	Если НЕ ЗначениеЗаполнено(АдресныеСведения.Данные) ИЛИ АдресныеСведения.Отказ = Истина Тогда
		Возврат Адрес;
	КонецЕсли;
	
	ЗаполнитьЗначенияСвойств(Адрес, АдресныеСведения.Данные, "addressType,codeKLADR,id,ifnsFLAreaCode,ifnsFLCode,ifnsULAreaCode,ifnsULCode,okato,oktmo,
	|ZIPCode,value,admLevels,munLevels,areaValue");
	
	Если ПустаяСтрока(Адрес.Country) Тогда
		Адрес.Вставить("Country", Строка(РаботаСАдресамиКлиентСервер.ОсновнаяСтрана()));
	КонецЕсли;

	СтруктураДанных = АдресныеСведения.Данные;
	Для каждого ИмяУровня Из СопоставлениеУровнейАдреса() Цикл
		
		Адрес[ИмяУровня]          = СтруктураДанных[ИмяУровня];
		Адрес[ИмяУровня + "Type"] = СтруктураДанных[ИмяУровня + "Type"];
		Адрес[ИмяУровня + "Id"]   = СтруктураДанных[ИмяУровня + "Id"];
		
	КонецЦикла;
	
	Возврат Адрес;
КонецФункции

Функция СопоставлениеУровнейАдреса()
	
	Уровни = Новый Массив;
	Уровни.Добавить("area");
	Уровни.Добавить("munDistrict");
	Уровни.Добавить("district");
	Уровни.Добавить("settlement");
	Уровни.Добавить("city");
	Уровни.Добавить("locality");
	Уровни.Добавить("territory");
	Уровни.Добавить("street");
	
	Возврат Уровни;
	
КонецФункции

Процедура ПроверитьАдрес(АдресВXML, РезультатПроверки, ПараметрыПроверкиАдреса = Неопределено) Экспорт
	
	Если ПустаяСтрока(АдресВXML) Тогда
		РезультатПроверки.Результат = "НеПроверен";
		Возврат;
	КонецЕсли;
	
	Адрес = УправлениеКонтактнойИнформацией.КонтактнаяИнформацияВJSON(АдресВXML);
	
	ТолькоНациональныйАдрес = Истина;
	Если ТипЗнч(ПараметрыПроверкиАдреса) = Тип("СправочникСсылка.ВидыКонтактнойИнформации") Тогда
		ПараметрыПроверки = УправлениеКонтактнойИнформациейСлужебный.СтруктураВидаКонтактнойИнформации(ПараметрыПроверкиАдреса);
		ТолькоНациональныйАдрес = ПараметрыПроверки.ТолькоНациональныйАдрес;
	Иначе
		ПараметрыПроверки = УправлениеКонтактнойИнформациейСлужебный.СтруктураВидаКонтактнойИнформации();
		Если ПараметрыПроверкиАдреса <> Неопределено Тогда
			Если ПараметрыПроверкиАдреса.Свойство("ТолькоНациональныйАдрес") И ЗначениеЗаполнено(ПараметрыПроверкиАдреса.ТолькоНациональныйАдрес) Тогда
				ТолькоНациональныйАдрес = ПараметрыПроверкиАдреса.ТолькоНациональныйАдрес;
			КонецЕсли;
		КонецЕсли;
		ПараметрыПроверки.ПроверятьКорректность = Истина;
	КонецЕсли;
	
	ПараметрыПроверки.Вставить("ТолькоНациональныйАдрес ", ТолькоНациональныйАдрес);
	СписокОшибок = ОшибкиЗаполненияАдреса(Адрес, ПараметрыПроверки);
	ОписаниеОшибок = Новый СписокЗначений;
	
	Если СписокОшибок.Количество() = 0 Тогда
		РезультатПроверки.Результат = "Корректный";
	Иначе
		Если НЕ СписокОшибок[0].АдресПроверен Тогда
			РезультатПроверки.Результат = "НеПроверен";
		Иначе
			РезультатПроверки.Результат = "СодержитОшибки";
		КонецЕсли;
		Для каждого ОписаниеОшибки Из СписокОшибок Цикл
			ОписаниеОшибок.Добавить(ОписаниеОшибки.ИмяПоля, ОписаниеОшибки.ТекстОшибки, ОписаниеОшибки.АдресПроверен);
		КонецЦикла;
	КонецЕсли;
	
	РезультатПроверки.СписокОшибок = ОписаниеОшибок;
	
КонецПроцедуры

// Возвращает данные классификатора по почтовому индексу.
//
// Параметры:
//     Индекс - Строка
//            - Число - почтовый индекс, для которого необходимо получать данные.
//
//     ДополнительныеПараметры - Структура - описывает настройки поиска. Состоит из необязательных полей:
//         * СкрыватьНеактуальные - Булево - флаг исключения из выборки неактуальных адресов. По умолчанию Ложь.
//         * ФорматАдреса - Строка - тип используемого классификатора.
//
// Возвращаемое значение:
//     Структура -  найденные варианты. Содержит поля:
//       * Отказ                        - Булево - поставщик не доступен.
//       * ПодробноеПредставлениеОшибки - Строка - описание ошибки, если поставщик недоступен. Неопределено, если Отказ
//                                                 = Ложь.
//       * КраткоеПредставлениеОшибки   - Строка - описание ошибки, если поставщик недоступен. Неопределено, если Отказ
//                                                 = Ложь.
//       * ОбщаяЧастьПредставления      - Строка - общая часть представлений адреса.
//       * Данные                       - ТаблицаЗначений - содержит данные для выбора. Колонки:
//                                           ** Неактуален    - Булево - флаг неактуальности строки данных.
//                                           ** Идентификатор - УникальныйИдентификатор - код классификатора для поиска
//                                                                                        вариантов по индексу.
//                                           ** Представление - Строка - представление варианта.
//
Функция АдресаКлассификатораПоПочтовомуИндексу(Знач Индекс, Знач ДополнительныеПараметры) Экспорт
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.АдресныйКлассификатор") Тогда
		
		ТипЧисло = Новый ОписаниеТипов("Число");
		ИндексЧислом = ТипЧисло.ПривестиЗначение(Индекс);
		
		МодульАдресныйКлассификаторСлужебный = ОбщегоНазначения.ОбщийМодуль("АдресныйКлассификаторСлужебный");
		Возврат МодульАдресныйКлассификаторСлужебный.АдресаПоПочтовомуИндексуКлассификатора(ИндексЧислом, ДополнительныеПараметры);
		
	КонецЕсли;
	
	Результат = СтруктураОшибкиПоставщикаАдресногоКлассификатора();
	Результат.Вставить("Данные", Новый ТаблицаЗначений);
	Возврат Результат;
	
КонецФункции

// Возвращает данные классификатора поля выбора по уровню.
//
// Параметры:
//     Родитель                - УникальныйИдентификатор - родительский объект.
//     Уровень                 - Число                   - требуемый уровень данных.
//     ДополнительныеПараметры - Структура - описание настроек поиска:
//         * СкрыватьНеактуальные              - Булево - флаг исключения из выборки неактуальных адресов. По умолчанию
//                                                        Ложь.
//         * ФорматАдреса - Строка - тип используемого классификатора.
//
//         * РазмерПорции - Число                   - необязательный размер порции возвращаемых данных. Если не указано
//                                                    или 0, то возвращает все элементы.
//         * ПерваяЗапись - УникальныйИдентификатор - элемент, с которого начинается порция данных. Сам элемент не
//                                                    входит в выборку.
//         * Сортировка   - Строка                  - направление сортировки для порции.
//
// Возвращаемое значение:
//     Структура -  найденные варианты. Содержит поля:
//       * Отказ                        - Булево - поставщик не доступен.
//       * ПодробноеПредставлениеОшибки - Строка - описание ошибки, если поставщик недоступен. Неопределено, если Отказ
//                                                 = Ложь.
//       * КраткоеПредставлениеОшибки   - Строка - описание ошибки, если поставщик недоступен. Неопределено, если Отказ
//                                                 = Ложь.
//       * Заголовок                    - Строка - строка с предложением выбора.
//       * Данные                       - ТаблицаЗначений - содержит данные для выбора. Колонки:
//             ** Неактуален    - Булево - флаг неактуальности строки данных.
//             ** Идентификатор - УникальныйИдентификатор - код классификатора для поиска вариантов по индексу.
//             ** Представление - Строка - представление варианта.
//
Функция АдресаДляИнтерактивногоВыбора(Родитель, Уровень, ТипАдреса, ДополнительныеПараметры) Экспорт
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.АдресныйКлассификатор") Тогда
		МодульАдресныйКлассификаторСлужебный = ОбщегоНазначения.ОбщийМодуль("АдресныйКлассификаторСлужебный");
		Возврат МодульАдресныйКлассификаторСлужебный.АдресаДляИнтерактивногоВыбора(Родитель, Уровень, ТипАдреса, ДополнительныеПараметры);
	КонецЕсли;
	
	Результат = СтруктураОшибкиПоставщикаАдресногоКлассификатора();
	Результат.Вставить("Заголовок", "");
	Результат.Вставить("Данные", Новый ТаблицаЗначений);
	Возврат Результат;

КонецФункции

// Возвращает структуру с полем "Данные", содержащую список для автоподбора населенного пункта 
//  по иерархическому представлению младший-старший.
//
//  Параметры:
//      Текст                                - Строка - текст автоподбора.
//      ДополнительныеПараметры              - Структура - описывает настройки поиска. Состоит из необязательных полей:
//         * СкрыватьНеактуальные              - Булево - флаг исключения из выборки неактуальных адресов. По умолчанию
//                                                        Ложь.
//         * ФорматАдреса - Строка - тип используемого классификатора.
//
// Возвращаемое значение:
//  Структура:
//    * Данные                       - СписокЗначений - результат для автоподбора.
//    * Отказ                        - Булево - поставщик не доступен.
//    * ПодробноеПредставлениеОшибки - Строка - описание ошибки, если поставщик недоступен. Неопределено, если Отказ
//                                                 = Ложь.
//    * КраткоеПредставлениеОшибки   - Строка - описание ошибки, если поставщик недоступен. Неопределено, если Отказ
//                                                 = Ложь.
//
Функция СписокАвтоподбораНаселенногоПункта(Текст, ДополнительныеПараметры) Экспорт
	
	Результат = Новый Структура;
	Результат.Вставить("Данные",                       Новый СписокЗначений);
	Результат.Вставить("Отказ",                        Ложь);
	Результат.Вставить("ПодробноеПредставлениеОшибки", Неопределено);
	Результат.Вставить("КраткоеПредставлениеОшибки",   Неопределено);
	
	Если Не ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.АдресныйКлассификатор") Тогда
		Результат.Отказ                        = Истина;
		Результат.КраткоеПредставлениеОшибки   = НСтр("ru = 'Адресные сведения отсутствуют.'");
		Результат.ПодробноеПредставлениеОшибки = "";
		Возврат Результат;
	КонецЕсли;
	
	МодульАдресныйКлассификаторСлужебный = ОбщегоНазначения.ОбщийМодуль("АдресныйКлассификаторСлужебный");
	Результат.Данные = МодульАдресныйКлассификаторСлужебный.ВариантыАвтоподбора(Текст, ДополнительныеПараметры);
	
	Возврат Результат;
КонецФункции

// Возвращает структуру с полем "Данные", содержащую список для автоподбора улицы
//  по иерархическому представлению младший-старший.
//
//  Параметры:
//      Текст                   - Строка - текст автоподбора.
//      ПараметрыАвтоподбора - Структура - описывает настройки поиска. Состоит из необязательных полей:
//         * Идентификатор               - УникальныйИдентификатор - родительский адресный объект.
//         * ТипАдреса                   - Строка - тип используемого адреса.
//
// Возвращаемое значение:
//    см. АдресныйКлассификаторСлужебный.АдресныеОбъектыУровня
//
Функция СписокАвтоподбораУлицы(Текст, ПараметрыАвтоподбора) Экспорт
	
	Уровень                   = 8;
	РодительскийИдентификатор = ПараметрыАвтоподбора.Идентификатор;
	ТипАдреса                 = ПараметрыАвтоподбора.ТипАдреса;
	
	МодульАдресныйКлассификаторСлужебный = ОбщегоНазначения.ОбщийМодуль("АдресныйКлассификаторСлужебный");
	Результат = МодульАдресныйКлассификаторСлужебный.АдресныеОбъектыУровня(РодительскийИдентификатор, Уровень, ТипАдреса, Текст);
	
	Возврат Результат;
	
КонецФункции

// Возвращает список значение содержащий номера домов для автоподбора.
//
//  Параметры:
//      ИдентификаторАдресногоОбъекта         - УникальныйИдентификатор - населенный пункт или улица.
//      СтрокаПоиска                   - Строка - текст автоподбора.
// Возвращаемое значение:
//       СписокЗначений - результат для автоподбора.
//
Функция СписокАвтоподбораНомераДомов(ИдентификаторАдресногоОбъекта, СтрокаПоиска) Экспорт
	
	ВариантыДомов = Новый СписокЗначений;
	
	СписокДомов = СписокДомов(ИдентификаторАдресногоОбъекта, СтрокаПоиска);
	Если СписокДомов <> Неопределено Тогда
		ВариантыДомов = Новый СписокЗначений;
		Для каждого Строка Из СписокДомов Цикл
			ВариантыДомов.Добавить(Строка.Значение, Строка.Представление);
		КонецЦикла;
	КонецЕсли;
	
	Возврат ВариантыДомов;
КонецФункции

// Возвращает список домов по идентификатору адресного объекта, поиск по подобию.
//
// Параметры:
//     ИдентификаторАдресногоОбъекта - УникальныйИдентификатор - родительский объект.
//     СтрокаПоиска                  - Строка                  - текст, отбора в списке домов.
//
// Возвращаемое значение:
//   см. АдресныйКлассификаторСлужебный.КонструкторСпискаДомов
//
Функция СписокДомов(ИдентификаторАдресногоОбъекта, СтрокаПоиска = "", ПорцияПриПоиске = 20) Экспорт
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.АдресныйКлассификатор") Тогда
		МодульАдресныйКлассификаторСлужебный = ОбщегоНазначения.ОбщийМодуль("АдресныйКлассификаторСлужебный");
		СписокДомов = МодульАдресныйКлассификаторСлужебный.СписокДомов(ИдентификаторАдресногоОбъекта, СтрокаПоиска, ПорцияПриПоиске);
		Возврат СписокДомов;
	КонецЕсли;
	
	Возврат Неопределено;
	
КонецФункции

#КонецОбласти

//======================================================================================================================
// Служебные

// Внутреннее для сериализации.
Функция ДесериализацияАдресаОбщая(Знач ЗначенияПолей, Знач Представление, Знач ОжидаемыйТип = Неопределено)
	
	Если УправлениеКонтактнойИнформациейКлиентСервер.ЭтоКонтактнаяИнформацияВXML(ЗначенияПолей) Тогда
		// Общий формат контактной информации.
		Возврат УправлениеКонтактнойИнформациейЛокализация.КонтактнаяИнформацияИзXML(ЗначенияПолей, ОжидаемыйТип);
	КонецЕсли;
	
	Если ОжидаемыйТип <> Неопределено Тогда
		Если ОжидаемыйТип <> Перечисления.ТипыКонтактнойИнформации.Адрес Тогда
			ВызватьИсключение НСтр("ru = 'Ошибка десериализации контактной информации, ожидается адрес'");
		КонецЕсли;
	КонецЕсли;
	
	// Старый формат через разделитель строк и равенство.
	ПространствоИмен = УправлениеКонтактнойИнформациейЛокализация.ПространствоИмен();
	
	Результат = ФабрикаXDTO.Создать(ФабрикаXDTO.Тип(ПространствоИмен, "КонтактнаяИнформация"));
	
	Результат.Комментарий = "";
	Результат.Состав      = ФабрикаXDTO.Создать(ФабрикаXDTO.Тип(ПространствоИмен, "Адрес"));
	
	НазваниеОсновнойСтраны  = ВРег(ОбщегоНазначения.ЗначениеРеквизитаОбъекта(
		РаботаСАдресамиКлиентСервер.ОсновнаяСтрана(), "Наименование"));
	ЭлементКвартира = Неопределено;
	ЭлементКорпус   = Неопределено;
	ЭлементДом      = Неопределено;
	
	// Национальный
	НациональныйАдрес = ФабрикаXDTO.Создать(ФабрикаXDTO.Тип(РаботаСАдресами.ПространствоИмен(), "АдресРФ"));
	
	// Общий состав
	Адрес = Результат.Состав;
	Адрес.Страна = НазваниеОсновнойСтраны; // Страна по умолчанию
	АдресРоссийский = Истина;
	
	ТипЗначенийПолей = ТипЗнч(ЗначенияПолей);
	Если ТипЗначенийПолей = Тип("СписокЗначений") Тогда
		СписокПолей = ЗначенияПолей;
	ИначеЕсли ТипЗначенийПолей = Тип("Структура") Тогда
		СписокПолей = УправлениеКонтактнойИнформациейСлужебный.ПреобразоватьСтрокуВСписокПолей(
			РаботаСАдресами.СтрокаПолей(ЗначенияПолей, Ложь));
	Иначе
		// Уже преобразовано в строку
		СписокПолей = УправлениеКонтактнойИнформациейСлужебный.ПреобразоватьСтрокуВСписокПолей(ЗначенияПолей);
	КонецЕсли;
	
	ТипКвартирыНеопределен = Истина;
	ТипКорпусаНеопределен  = Истина;
	ТипДомаНеопределен     = Истина;
	ПолеПредставления      = "";
	
	Для Каждого ЭлементСписка Из СписокПолей Цикл
		ИмяПоля = ВРег(ЭлементСписка.Представление);
		
		Если ИмяПоля="ИНДЕКС" Тогда
			ЭлементИндекс = СоздатьДопАдрЭлемента(НациональныйАдрес);
			ЭлементИндекс.ТипАдрЭл = РаботаСАдресами.КодСериализацииПочтовогоИндекса();
			ЭлементИндекс.Значение = ЭлементСписка.Значение;
			
		ИначеЕсли ИмяПоля = "СТРАНА" Тогда
			Адрес.Страна = ЭлементСписка.Значение;
			Если ВРег(ЭлементСписка.Значение) <> НазваниеОсновнойСтраны Тогда
				АдресРоссийский = Ложь;
			КонецЕсли;
			
		ИначеЕсли ИмяПоля = "КОДСТРАНЫ" Тогда
			// действия не требуется
			
		ИначеЕсли ИмяПоля = "КОДРЕГИОНА" Тогда
			НациональныйАдрес.СубъектРФ = РегионКода(ЭлементСписка.Значение);
			
		ИначеЕсли ИмяПоля = "РЕГИОН" Тогда
			НациональныйАдрес.СубъектРФ = ЭлементСписка.Значение;
			
		ИначеЕсли ИмяПоля = "РАЙОН" Тогда
			Если НациональныйАдрес.СвРайМО = Неопределено Тогда
				НациональныйАдрес.СвРайМО = ФабрикаXDTO.Создать( НациональныйАдрес.Тип().Свойства.Получить("СвРайМО").Тип )
			КонецЕсли;
			НациональныйАдрес.СвРайМО.Район = ЭлементСписка.Значение;
			
		ИначеЕсли ИмяПоля = "ГОРОД" Тогда
			НациональныйАдрес.Город = ЭлементСписка.Значение;
			
		ИначеЕсли ИмяПоля = "НАСЕЛЕННЫЙПУНКТ" Тогда
			НациональныйАдрес.НаселПункт = ЭлементСписка.Значение;
			
		ИначеЕсли ИмяПоля = "УЛИЦА" Тогда
			НациональныйАдрес.Улица = ЭлементСписка.Значение;
			
		ИначеЕсли ИмяПоля = "ТИПДОМА" Тогда
			Если ЭлементДом = Неопределено Тогда
				ЭлементДом = СоздатьНомерДопАдрЭлемента(НациональныйАдрес);
			КонецЕсли;
			ЭлементДом.Тип = РаботаСАдресами.КодСериализацииОбъектаАдресации(ЭлементСписка.Значение);
			ТипДомаНеопределен = Ложь;
			
		ИначеЕсли ИмяПоля = "ДОМ" Тогда
			Если ЭлементДом = Неопределено Тогда
				ЭлементДом = СоздатьНомерДопАдрЭлемента(НациональныйАдрес);
			КонецЕсли;
			ЭлементДом.Значение = ЭлементСписка.Значение;
			
		ИначеЕсли ИмяПоля = "ТИПКОРПУСА" Тогда
			Если ЭлементКорпус = Неопределено Тогда
				ЭлементКорпус = СоздатьНомерДопАдрЭлемента(НациональныйАдрес);
			КонецЕсли;
			ЭлементКорпус.Тип = РаботаСАдресами.КодСериализацииОбъектаАдресации(ЭлементСписка.Значение);
			ТипКорпусаНеопределен = Ложь;
			
		ИначеЕсли ИмяПоля = "КОРПУС" Тогда
			Если ЭлементКорпус = Неопределено Тогда
				ЭлементКорпус = СоздатьНомерДопАдрЭлемента(НациональныйАдрес);
			КонецЕсли;
			ЭлементКорпус.Значение = ЭлементСписка.Значение;
			
		ИначеЕсли ИмяПоля = "ТИПКВАРТИРЫ" Тогда
			Если ЭлементКвартира = Неопределено Тогда
				ЭлементКвартира = СоздатьНомерДопАдрЭлемента(НациональныйАдрес);
			КонецЕсли;
			ЭлементКвартира.Тип = РаботаСАдресами.КодСериализацииОбъектаАдресации(ЭлементСписка.Значение);
			ТипКвартирыНеопределен = Ложь;
			
		ИначеЕсли ИмяПоля = "КВАРТИРА" Тогда
			Если ЭлементКвартира = Неопределено Тогда
				ЭлементКвартира = СоздатьНомерДопАдрЭлемента(НациональныйАдрес);
			КонецЕсли;
			ЭлементКвартира.Значение = ЭлементСписка.Значение;
			
		ИначеЕсли ИмяПоля = "ПРЕДСТАВЛЕНИЕ" Тогда
			ПолеПредставления = СокрЛП(ЭлементСписка.Значение);
			
		КонецЕсли;
		
	КонецЦикла;
	
	// Умолчания
	Если ТипДомаНеопределен И ЭлементДом <> Неопределено Тогда
		ЭлементДом.Тип = РаботаСАдресами.КодСериализацииОбъектаАдресации("Дом");
	КонецЕсли;
	
	Если ТипКорпусаНеопределен И ЭлементКорпус <> Неопределено Тогда
		ЭлементКорпус.Тип = РаботаСАдресами.КодСериализацииОбъектаАдресации("Корпус");
	КонецЕсли;
	
	Если ТипКвартирыНеопределен И ЭлементКвартира <> Неопределено Тогда
		ЭлементКвартира.Тип = РаботаСАдресами.КодСериализацииОбъектаАдресации("Квартира");
	КонецЕсли;
	
	// Представление с приоритетами.
	Если Не ПустаяСтрока(Представление) Тогда
		Результат.Представление = Представление;
	ИначеЕсли ЗначениеЗаполнено(ПолеПредставления) Или ТипЗначенийПолей = Тип("СписокЗначений") Тогда
		Результат.Представление = ПолеПредставления;
	Иначе
		Результат.Представление = РаботаСАдресамиКлиентСервер.ПредставлениеАдреса(Результат, Истина);
	КонецЕсли;
	
	Адрес.Состав = ?(АдресРоссийский, НациональныйАдрес, Результат.Представление);
	
	Возврат Результат;
КонецФункции

// Преобразует строку в XDTO контактную информацию адреса.
//
//  Параметры:
//      ЗначенияПолей - Строка - сериализованная информация, значения полей.
//      Представление - Строка - представление старший-младший, используется для попытки разбора, если ЗначенияПолей
//                               пусто.
//      ОжидаемыйТип  - ПеречислениеСсылка.ТипыКонтактнойИнформации - тип для контроля.
//
//  Возвращаемое значение:
//      ОбъектXDTO  - контактной информации.
//
Функция АдресXMLВXDTO(Знач ЗначенияПолей, Знач Представление = "", Знач ОжидаемыйТип = Неопределено) Экспорт
	
	Если Метаданные.Обработки.Найти("РасширенныйВводКонтактнойИнформации") <> Неопределено Тогда
		
		ТипЗначения = ТипЗнч(ЗначенияПолей);
		РазбиратьПоПолям = (ТипЗначения = Тип("СписокЗначений") Или ТипЗначения = Тип("Структура")
			Или (ТипЗначения = Тип("Строка") И Не ПустаяСтрока(ЗначенияПолей)));
		Если РазбиратьПоПолям Тогда
			// Разбираем из значений полей.
			Возврат ДесериализацияАдресаОбщая(ЗначенияПолей, Представление, ОжидаемыйТип);
		КонецЕсли;
		
		// Разбираем адрес из его представления по классификатору.
		Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.АдресныйКлассификатор") Тогда
			Возврат СформироватьАдресПоПредставлению(Представление);
		КонецЕсли;
		
	КонецЕсли;
	
	// Пустой объект с представлением.
	ПространствоИмен = УправлениеКонтактнойИнформациейЛокализация.ПространствоИмен();
	Результат = ФабрикаXDTO.Создать(ФабрикаXDTO.Тип(ПространствоИмен, "КонтактнаяИнформация"));
	Результат.Состав = ФабрикаXDTO.Создать(ФабрикаXDTO.Тип(ПространствоИмен, "Адрес"));
	Результат.Состав.Состав = Представление;
	Результат.Представление = Представление;
	Возврат Результат;
	
КонецФункции

Функция СформироватьАдресПоПредставлению(Представление)
	
	Адрес = УправлениеКонтактнойИнформацией.КонтактнаяИнформацияПоПредставлению(Представление, Перечисления.ТипыКонтактнойИнформации.Адрес);
	АдресВXML = УправлениеКонтактнойИнформацией.КонтактнаяИнформацияВXML(Адрес, Представление, Перечисления.ТипыКонтактнойИнформации.Адрес);
	Возврат УправлениеКонтактнойИнформациейЛокализация.АдресXMLВXDTO(АдресВXML, Представление, Перечисления.ТипыКонтактнойИнформации.Адрес);
	
КонецФункции

// Возвращает представление младший-старший для населенного пункта.
//
//  Параметры:
//      ОбъектАдреса - ОбъектXDTO - адрес РФ.
//
//  Возвращаемое значение:
//      Строка - представление.
//
Функция ПредставлениеНаселенногоПункта(ОбъектАдреса) Экспорт
	
	СписокПолей = РаботаСАдресамиКлиентСервер.ИменаУровнейАдресаПоАдресу(ОбъектАдреса, Ложь, Ложь);
	
	Адрес = Новый Массив;
	Для каждого ИмяПоля Из СписокПолей Цикл
		
		Если ОбъектАдреса.Свойство(ИмяПоля) И ЗначениеЗаполнено(ОбъектАдреса[ИмяПоля]) Тогда
			
			Если СтрСравнить(ИмяПоля, "munDistrict") = 0 Тогда
				НаименованиеУровня  =  РаботаСАдресамиКлиентСервер.КраткоеНаписаниеМуниципальныхРайонов(ОбъектАдреса[ИмяПоля], ОбъектАдреса[ИмяПоля + "Type"]);
			ИначеЕсли СтрСравнить(ИмяПоля, "settlement") = 0 Тогда
				НаименованиеУровня  = РаботаСАдресамиКлиентСервер.КраткоеНаписаниеПоселений(ОбъектАдреса[ИмяПоля], ОбъектАдреса[ИмяПоля + "Type"]);
			Иначе
				НаименованиеУровня = ОбъектАдреса[ИмяПоля];
			КонецЕсли;
			
			ЭтоУровеньРегиона = СтрСравнить(ИмяПоля, "area") = 0;
			
			Если ЭтоУровеньРегиона И ЗначениеЗаполнено(ОбъектАдреса.areaValue) Тогда
				ПредставлениеУровня = ОбъектАдреса.areaValue;
			Иначе 
				ПредставлениеУровня = УправлениеКонтактнойИнформациейКлиентСервер.СоединитьНаименованиеИТипАдресногоОбъекта(НаименованиеУровня, 
					ОбъектАдреса[ИмяПоля + "Type"], ЭтоУровеньРегиона);
			КонецЕсли;
			
			ПредставлениеУровня = УправлениеКонтактнойИнформациейКлиентСервер.СоединитьНаименованиеИТипАдресногоОбъекта(НаименованиеУровня, 
				ОбъектАдреса[ИмяПоля + "Type"], СтрСравнить(ИмяПоля, "area") = 0);
			
			Адрес.Добавить(СокрЛП(ПредставлениеУровня));
		КонецЕсли;
		
	КонецЦикла;
	
	Возврат СтрСоединить(Адрес, ", ");
	
КонецФункции

//======================================================================================================================
// Структура и поля адреса.

// Возвращает извлеченный XDTO российского адреса или Неопределено для адреса иностранного.
//
//  Параметры:
//      ОбъектИнформации - ОбъектXDTO - контактная информация или XDTO адреса.
//
//  Возвращаемое значение:
//      ОбъектXDTO - российский адрес.
//      Неопределено - нет российского адреса.
//
Функция НациональныйАдрес(ОбъектИнформации)
	Результат = Неопределено;
	ТипXDTO   = Тип("ОбъектXDTO");
	
	Если ТипЗнч(ОбъектИнформации) = ТипXDTO Тогда
		ПространствоИмен = УправлениеКонтактнойИнформациейЛокализация.ПространствоИмен();
		
		Если ОбъектИнформации.Тип() = ФабрикаXDTO.Тип(ПространствоИмен, "КонтактнаяИнформация") Тогда
			Адрес = ОбъектИнформации.Состав;
		Иначе
			Адрес = ОбъектИнформации;
		КонецЕсли;
		
		Если ТипЗнч(Адрес) = ТипXDTO И Адрес.Тип() = ФабрикаXDTO.Тип(ПространствоИмен, "Адрес") Тогда
			Адрес = Адрес.Состав;
		КонецЕсли;
		
		Если ТипЗнч(Адрес) = ТипXDTO Тогда
			Результат = Адрес;
		КонецЕсли;
	КонецЕсли;
	
	Возврат Результат;
КонецФункции

// Читает и устанавливает почтовый индекс адреса.
//
//  Параметры:
//      XDTOАдрес     - ОбъектXDTO - контактная информация или XDTO адреса.
//      НовоеЗначение - Строка     - устанавливаемое значение.
//
//  Возвращаемое значение:
//      Строка - почтовый индекс.
//
Функция ПочтовыйИндексАдреса(XDTOАдрес, НовоеЗначение = Неопределено) Экспорт
	
	АдресРФ = НациональныйАдрес(XDTOАдрес);
	Если АдресРФ = Неопределено Тогда
		Возврат Неопределено;
	КонецЕсли;
	
	Если НовоеЗначение = Неопределено Тогда
		// Чтение
		Результат = АдресРФ.Получить(РаботаСАдресами.XPathПочтовогоИндекса() );
		Если Результат <> Неопределено Тогда
			Результат = Результат.Значение;
		КонецЕсли;
		Возврат Результат;
	КонецЕсли;
	
	// Запись
	КодИндекса = РаботаСАдресами.КодСериализацииПочтовогоИндекса();
	
	ЗаписьИндекса = АдресРФ.Получить(РаботаСАдресами.XPathПочтовогоИндекса());
	Если ЗаписьИндекса = Неопределено Тогда
		ДопАдрЭл = АдресРФ.ДопАдрЭл; // СписокXDTO
		ЗаписьИндекса = ДопАдрЭл.Добавить(ФабрикаXDTO.Создать(XDTOАдрес.ДопАдрЭл.ВладеющееСвойство.Тип));
		ЗаписьИндекса.ТипАдрЭл = КодИндекса;
	КонецЕсли;
	
	ЗаписьИндекса.Значение = СокрЛП(НовоеЗначение);
	Возврат НовоеЗначение;
КонецФункции

// Читает и устанавливает район адреса.
//
//  Параметры:
//      XDTOАдрес     - ОбъектXDTO - контактная информация или XDTO адреса.
//      НовоеЗначение - Строка - устанавливаемое значение.
//
//  Возвращаемое значение:
//      Строка - новое значение.
//
Функция РайонАдреса(XDTOАдрес, НовоеЗначение = Неопределено)
	
	Если НовоеЗначение = Неопределено Тогда
		// Чтение
		
		XDTOТип = XDTOАдрес.Тип();
		Если XDTOТип = ФабрикаXDTO.Тип(РаботаСАдресами.ПространствоИмен(), "АдресРФ") Тогда
			АдресРФ = XDTOАдрес;
		Иначе
			АдресРФ = XDTOАдрес.Состав;
		КонецЕсли;
		
		Если ТипЗнч(АдресРФ) = Тип("ОбъектXDTO") Тогда
			Возврат ПолучитьXDTOРеквизитОбъекта(АдресРФ, РаботаСАдресами.XPathРайона());
		КонецЕсли;
		
		Возврат Неопределено;
	КонецЕсли;
	
	// Запись
	Запись = СвРайМО(XDTOАдрес);
	Запись.Район = НовоеЗначение;
	Возврат НовоеЗначение;
КонецФункции

Функция СвРайМО(АдресРФ)
	Если АдресРФ.СвРайМО <> Неопределено Тогда
		Возврат АдресРФ.СвРайМО;
	КонецЕсли;
	
	АдресРФ.СвРайМО = ФабрикаXDTO.Создать(АдресРФ.Свойства().Получить("СвРайМО").Тип);
	Возврат АдресРФ.СвРайМО;
КонецФункции

// Возвращает значения уровней 90(дополнительный элемент) и 91(подчиненный) из адреса.
//
Функция ЗначениеДополнительныхЭлементов(Знач XDTOАдрес) Экспорт
	
	Результат = Новый Структура("ДополнительныйЭлемент, ПодчиненныйЭлемент");
	
	АдресРФ = НациональныйАдрес(XDTOАдрес);
	Если АдресРФ = Неопределено Тогда
		Возврат Результат;
	КонецЕсли;
	
	
	ДополнительныйЭлементАдреса = НайтиДополнительныйЭлементАдреса(АдресРФ).Значение;

	Результат.ДополнительныйЭлемент = ДополнительныйЭлементАдреса;
	Результат.ПодчиненныйЭлемент = ДополнительныйЭлементАдреса(АдресРФ, РаботаСАдресами.XPathДополнительногоОбъектаАдресации(91));
	
	Возврат Результат;
	
КонецФункции

// Читает дополнительные элемент адреса по его пути.
//
//  Параметры:
//      XDTOАдрес     - ОбъектXDTO - контактная информация или XDTO адреса.
//      XPathЭлемента -  Строка - путь к элементу.
//
//  Возвращаемое значение:
//      Строка - значение элемента.
//
Функция ДополнительныйЭлементАдреса(XDTOАдрес, XPathЭлемента)
	
	АдресРФ = НациональныйАдрес(XDTOАдрес);
	Если АдресРФ = Неопределено Тогда
		Возврат Неопределено;
	КонецЕсли;
	
	Результат = АдресРФ.Получить(XPathЭлемента);
	Если Результат <> Неопределено Тогда
		Возврат Результат.Значение;
	КонецЕсли;
	
	Возврат Результат;
КонецФункции

// Возвращает дополнительный адреса.
//
Функция НайтиДополнительныйЭлементАдреса(АдресРФ)
	
	ВариантыДополнительногоЭлементаАдреса = ВариантыДополнительногоЭлементаАдреса();
	
	ПутьXPath = "";
	ДополнительныйЭлементАдреса = Неопределено;
	Для каждого ВариантДополнительныйЭлементАдреса Из ВариантыДополнительногоЭлементаАдреса Цикл
		ПутьXPath = РаботаСАдресами.XPathДополнительногоОбъектаАдресации(90, ВариантДополнительныйЭлементАдреса);
		ДополнительныйЭлементАдреса = ДополнительныйЭлементАдреса(АдресРФ, ПутьXPath);
		Если ДополнительныйЭлементАдреса <> Неопределено Тогда
			Прервать;
		КонецЕсли;
	КонецЦикла;
	
	Возврат Новый Структура("Значение, XPath", ДополнительныйЭлементАдреса, ПутьXPath);
	
КонецФункции

Функция ВариантыДополнительногоЭлементаАдреса()
	
	ВариантыДополнительногоЭлементаАдреса = Новый Массив;
	ВариантыДополнительногоЭлементаАдреса.Добавить("СНТ");
	ВариантыДополнительногоЭлементаАдреса.Добавить("ГСК");
	ВариантыДополнительногоЭлементаАдреса.Добавить("ТЕР");
	ВариантыДополнительногоЭлементаАдреса.Добавить("");
	Возврат ВариантыДополнительногоЭлементаАдреса;

КонецФункции

Функция СоздатьНомерДопАдрЭлемента(АдресРФ)
	ДопАдрЭл = СоздатьДопАдрЭлемента(АдресРФ);
	ДопАдрЭл.Номер = ФабрикаXDTO.Создать(ДопАдрЭл.Тип().Свойства.Получить("Номер").Тип);
	Возврат ДопАдрЭл.Номер;
КонецФункции

Функция СоздатьДопАдрЭлемента(АдресРФ)
	СвойствоДопАдрЭлемента = АдресРФ.ДопАдрЭл.ВладеющееСвойство;
	ДопАдрЭлемента = ФабрикаXDTO.Создать(СвойствоДопАдрЭлемента.Тип);
	АдресРФ.ДопАдрЭл.Добавить(ДопАдрЭлемента);
	Возврат ДопАдрЭлемента;
КонецФункции

// Читает и устанавливает здания и помещения адреса. 
//
//  Параметры:
//      XDTOАдрес     - ОбъектXDTO - контактная информация или XDTO адреса.
//      НовоеЗначение - Структура  - устанавливаемое значение. Ожидаются поля:
//                          * Здания - ТаблицаЗначений:
//                                        ** Тип      - Строка - тип внутреннего классификатора дополнительных адресных
//                                                               объектов. Например "Корпус".
//                                        ** Значение - Строка  - значение номера дома, квартиры и т.п.
//                          * Помещения - ТаблицаЗначений - с колонками, аналогично полю Здание.
//
//  Возвращаемое значение:
//      Структура - текущие данные. Содержит поля:
//          * Здания - ТаблицаЗначений:
//                        ** Тип        - Строка - тип внутреннего классификатора дополнительных адресных объектов.
//                                                 Например "Корпус".
//                        ** Сокращение - Строка - сокращение названия для использования в представлении.
//                        ** Значение   - Строка - значение номера дома, квартиры и т.п.
//                        ** ПутьXPath  - Строка - путь к значению объекта.
//          * Помещения - ТаблицаЗначений - с колонками, аналогично полю Здание.
//
Функция ЗданияИПомещенияАдреса(XDTOАдрес, НовоеЗначение = Неопределено) Экспорт
	
	Результат = Новый Структура("Здания, Помещения", 
		ТаблицаЗначений("Тип, Значение, Сокращение, ПутьXPath, Вид", "Тип, Вид"),
		ТаблицаЗначений("Тип, Значение, Сокращение, ПутьXPath, Вид", "Тип, Вид"));
	
	АдресРФ = НациональныйАдрес(XDTOАдрес);
	Если АдресРФ = Неопределено Тогда
		Возврат Результат;
	КонецЕсли;
	
	Если НовоеЗначение <> Неопределено Тогда
		// Запись
		Если НовоеЗначение.Свойство("Здания") Тогда
			Для Каждого Строка Из НовоеЗначение.Здания Цикл
				ВставитьЗданиеПомещение(XDTOАдрес, Строка.Тип, Строка.Значение);
			КонецЦикла;
		КонецЕсли;
		Если НовоеЗначение.Свойство("Помещения") Тогда
			Для Каждого Строка Из НовоеЗначение.Помещения Цикл
				ВставитьЗданиеПомещение(XDTOАдрес, Строка.Тип, Строка.Значение);
			КонецЦикла;
		КонецЕсли;
		Возврат НовоеЗначение
	КонецЕсли;
	
	// Чтение
	Для Каждого ДопЭлемент Из АдресРФ.ДопАдрЭл Цикл
		Если ДопЭлемент.Номер <> Неопределено Тогда
			КодОбъекта = ДопЭлемент.Номер.Тип;
			ТипОбъекта = РаботаСАдресами.ТипОбъектаПоКодуСериализации(КодОбъекта);
			Если ТипОбъекта <> Неопределено Тогда
				Вид = ТипОбъекта.Тип;
				Если Вид = 1 Или Вид = 2 Тогда
					НоваяСтрока = Результат.Здания.Добавить();
				ИначеЕсли Вид = 3 Тогда
					НоваяСтрока = Результат.Помещения.Добавить();
				Иначе
					НоваяСтрока = Неопределено;
				КонецЕсли;
				Если НоваяСтрока <> Неопределено Тогда
					НоваяСтрока.Тип        = ТипОбъекта.Наименование;
					НоваяСтрока.Значение   = ДопЭлемент.Номер.Значение;
					НоваяСтрока.Сокращение = ТипОбъекта.Сокращение;
					НоваяСтрока.ПутьXPath  = РаботаСАдресами.XPathНомераДополнительногоОбъектаАдресации(НоваяСтрока.Тип);
					НоваяСтрока.Вид        = Вид;
				КонецЕсли;
			Иначе
				НоваяСтрока = Результат.Помещения.Добавить();
				НоваяСтрока.Тип        = ДопЭлемент.Номер.Тип;
				НоваяСтрока.Значение   = ДопЭлемент.Номер.Значение;
				НоваяСтрока.Сокращение = ДопЭлемент.Номер.Тип;
				НоваяСтрока.ПутьXPath  = РаботаСАдресами.XPathНомераДополнительногоОбъектаАдресации("2000");
				НоваяСтрока.Вид        = 3;
			КонецЕсли;
		КонецЕсли;
	КонецЦикла;
	
	Результат.Здания.Сортировать("Вид");
	Результат.Помещения.Сортировать("Вид");
	
	Возврат Результат;
КонецФункции

Функция ЗначениеЗданияИлиПомещения(Данные, Варианты, ВсеЗначенияВарианта)
	
	Результат = ТаблицаЗначений("Тип, Значение");
	
	Для каждого СведенияОбОбъекте Из Данные Цикл
		Для каждого Вариант Из Варианты.ВариантыТипа Цикл
			Если СтрСравнить(Вариант, СведенияОбОбъекте.Тип) = 0 Тогда
				ЗаполнитьЗначенияСвойств(Результат.Добавить(), СведенияОбОбъекте);
				Если Не ВсеЗначенияВарианта Тогда
					Прервать;
				КонецЕсли;
			КонецЕсли;
		КонецЦикла;
	КонецЦикла;
	
	Возврат Результат;
	
КонецФункции

Процедура ВставитьЗданиеПомещение(XDTOАдрес, Тип, Значение)
	Если ПустаяСтрока(Значение) Тогда
		Возврат;
	КонецЕсли;
	
	Запись = XDTOАдрес.Получить(РаботаСАдресами.XPathНомераДополнительногоОбъектаАдресации(Тип));
	Если Запись = Неопределено Тогда
		Запись = XDTOАдрес.ДопАдрЭл.Добавить( ФабрикаXDTO.Создать(XDTOАдрес.ДопАдрЭл.ВладеющееСвойство.Тип));
		Запись.Номер = ФабрикаXDTO.Создать(Запись.Свойства().Получить("Номер").Тип);
		Запись.Номер.Значение = Значение;
		
		КодТипа = РаботаСАдресами.КодСериализацииОбъектаАдресации(Тип);
		Если КодТипа = Неопределено Тогда
			КодТипа = Тип;
		КонецЕсли;
		Запись.Номер.Тип = КодТипа
	Иначе
		Запись.Значение = Значение;
	КонецЕсли;
	
КонецПроцедуры

// Конструктор таблицы значений.
//
Функция ТаблицаЗначений(СписокКолонок, СписокИндексов = "")
	ТаблицаРезультата = Новый ТаблицаЗначений;
	
	Для Каждого КлючЗначение Из (Новый Структура(СписокКолонок)) Цикл
		ТаблицаРезультата.Колонки.Добавить(КлючЗначение.Ключ);
	КонецЦикла;
	
	СтрокиИндексов = СтрЗаменить(СписокИндексов, "|", Символы.ПС);
	Для НомерИндекса = 1 По СтрЧислоСтрок(СтрокиИндексов) Цикл
		КолонкиИндекса = СокрЛП(СтрПолучитьСтроку(СтрокиИндексов, НомерИндекса));
		Для Каждого КлючЗначение Из (Новый Структура(КолонкиИндекса)) Цикл
			ТаблицаРезультата.Индексы.Добавить(КлючЗначение.Ключ);
		КонецЦикла;
	КонецЦикла;
	
	Возврат ТаблицаРезультата;
КонецФункции

// Получение глубокого свойства объекта.
//
Функция ПолучитьXDTOРеквизитОбъекта(ОбъектXTDO, XPath)
	
	// Переносов строки в XPath не ожидаем.
	СтрокаСвойств = СтрЗаменить(СтрЗаменить(XPath, "/", Символы.ПС), Символы.ПС + Символы.ПС, "/");
	
	ЧислоСвойств = СтрЧислоСтрок(СтрокаСвойств);
	Если ЧислоСвойств = 1 Тогда
		Результат = ОбъектXTDO.Получить(СтрокаСвойств);
		Если ТипЗнч(Результат) = Тип("ОбъектXDTO") Тогда 
			Возврат Результат.Значение;
		КонецЕсли;
		Возврат Результат;
	КонецЕсли;
	
	Результат = ?(ЧислоСвойств = 0, Неопределено, ОбъектXTDO);
	Для Индекс = 1 По ЧислоСвойств Цикл
		Результат = Результат.Получить(СтрПолучитьСтроку(СтрокаСвойств, Индекс));
		Если Результат = Неопределено Тогда 
			Прервать;
		КонецЕсли;
	КонецЦикла;
	
	Возврат Результат;
КонецФункции

// Устанавливает в XDTO адресе значение по XPath.
//
Процедура УстановитьXDTOРеквизитОбъекта(ОбъектXDTO, ПутьXPath, Значение) Экспорт
	
	Если Значение = Неопределено Тогда
		Возврат;
	КонецЕсли;
	
	// Части XPath
	ЧастиПути  = СтрЗаменить(ПутьXPath, "/", Символы.ПС);
	ЧастейПути = СтрЧислоСтрок(ЧастиПути);
	
	ВедущийОбъект = ОбъектXDTO;
	Объект        = ОбъектXDTO;
	
	Для Позиция = 1 По ЧастейПути Цикл
		ЧастьПути = СтрПолучитьСтроку(ЧастиПути, Позиция);
		Если ЧастейПути = 1 Тогда
			Прервать;
		КонецЕсли;
		
		Свойство = Объект.Свойства().Получить(ЧастьПути);
		Если Не Объект.Установлено(Свойство) Тогда
			Объект.Установить(Свойство, ФабрикаXDTO.Создать(Свойство.Тип));
		КонецЕсли;
		ВедущийОбъект = Объект;
		Объект        = Объект[ЧастьПути];
	КонецЦикла;
	
	Если Объект <> Неопределено Тогда
		
		Если СтрНайти(ЧастьПути, "ДопАдрЭл") = 0 Тогда
			Объект[ЧастьПути] = Значение;
		Иначе
			КодПутьXPath = Сред(ЧастьПути, 20, 8);
			ЗначениеПоля = Объект.ДопАдрЭл.Добавить(ФабрикаXDTO.Создать(Объект.ДопАдрЭл.ВладеющееСвойство.Тип));
			ЗначениеПоля.ТипАдрЭл = КодПутьXPath;
			ЗначениеПоля.Значение = Значение;
		КонецЕсли;
		
	ИначеЕсли ВедущийОбъект <> Неопределено Тогда
		ВедущийОбъект[ЧастьПути] =  Значение;
		
	КонецЕсли;
	
КонецПроцедуры

//======================================================================================================================
// Проверка адреса


//======================================================================================================================
// Проверка адреса

// Возвращает перечень ошибок для адреса.
//
// Параметры:
//     Адрес         - ОбъектXDTO
//                   - СписокЗначений
//                   - Строка - описание адреса.
//     ВидИнформации     - СправочникСсылка.ВидыКонтактнойИнформации
//                       - Структура - ссылка на соответствующий вид
//                         контактной информации.
//     РезультатГруппами - Булево - если указана Истина, то будет возвращен массив групп ошибок, иначе - список
//                                  значений.
//
// Возвращаемое значение:
//     СписокЗначений - если параметр РезультатГруппами равен Ложь. Внутри представление - текст ошибки, значение -
//                      XPath ошибочного поля.
//     Массив из Структура  - если параметр РезультатГруппами равен Истина. Содержит структуры с полями:
//                         * ТипОшибки - Строка - наименование группы (типа) ошибки. Возможные значения.
//                               "ПредставлениеНеСоответствуетНаборуПолей"
//                               "НеЗаполненыОбязательныеПоля"
//                               "НеУказаныСокращенияПолей"
//                               "НедопустимыеСимволыПолей"
//                               "НеСоответствуетДлинаПолей"
//                               "ОшибкиПоКлассификатору".
//                         * Сообщение - Строка - подробный текст ошибки.
//                         * Поля      - Массив - содержит структуры описания ошибочных полей. Каждая структура имеет
//                                                 реквизиты:
//                               ** ИмяПоля   - Строка - внутренний идентификатор ошибочного элемента адреса.
//                               ** Сообщение - Строка - подробный текст ошибки для этого поля.
//
Функция ОшибкиЗаполненияАдреса(Знач Адрес, ВидИнформации) Экспорт
	
	Если ТипЗнч(Адрес) = Тип("ОбъектXDTO") Тогда
		АдресXML = УправлениеКонтактнойИнформациейЛокализация.КонтактнаяИнформацияXDTOВXML(Адрес);
		Адрес = УправлениеКонтактнойИнформацией.КонтактнаяИнформацияВJSON(АдресXML);
	КонецЕсли;
	
	Если ТипЗнч(Адрес) = Тип("Строка") Тогда
		Адрес = УправлениеКонтактнойИнформациейСлужебный.JSONВКонтактнуюИнформациюПоПолям(Адрес, Перечисления.ТипыКонтактнойИнформации.Адрес);
	КонецЕсли;
	
	СписокОшибок = Новый Массив;
	
	// Флаги проверки
	Если ТипЗнч(ВидИнформации) = Тип("СправочникСсылка.ВидыКонтактнойИнформации") Тогда
		ФлагиПроверки = УправлениеКонтактнойИнформациейСлужебный.СтруктураВидаКонтактнойИнформации(ВидИнформации);
	Иначе
		ФлагиПроверки = ВидИнформации;
	КонецЕсли;
	
	Если ФлагиПроверки.МеждународныйФорматАдреса Тогда
		
		Если УправлениеКонтактнойИнформациейКлиентСервер.ЭтоАдресВСвободнойФорме(Адрес.addressType) Тогда
			
			ПредставлениеАдреса = Адрес.value;
			Если ВидИнформации.ВключатьСтрануВПредставление Тогда
				ПредставлениеАдреса = СтрЗаменить(ПредставлениеАдреса, Адрес.country, "");
			КонецЕсли;
			ТолькоЛатиницаВСтроке(ПредставлениеАдреса, СписокОшибок);
			
		Иначе
		
			ИменаУровней = РаботаСАдресамиКлиентСервер.ИменаУровнейАдреса(Адрес.addressType, Истина);
		
			Для каждого ИмяУровня Из ИменаУровней Цикл
				
				ТолькоЛатиницаВСтроке(Адрес[ИмяУровня], СписокОшибок);
				Если СписокОшибок.Количество() > 0 Тогда
					Прервать;
				КонецЕсли;
				
			КонецЦикла;
			
		КонецЕсли;
		
		Возврат СписокОшибок;
	КонецЕсли;
	
	Если НЕ УправлениеКонтактнойИнформациейСлужебный.ЭтоНациональныйАдрес(Адрес) Тогда
		
		// Адрес за пределами РФ
		Если ФлагиПроверки.ТолькоНациональныйАдрес Тогда
			ТекстОшибки = НСтр("ru = 'Адрес должен быть только российским.'");
			СписокОшибок.Добавить(ПоляОшибки(ТекстОшибки, Ложь));
		КонецЕсли;
		
		Возврат СписокОшибок;
	КонецЕсли;
	
	// Адрес пустой
	Если Не УправлениеКонтактнойИнформациейСлужебный.КонтактнаяИнформацияЗаполнена(Адрес) Тогда
		
		Если ФлагиПроверки.ОбязательноеЗаполнение Тогда
			// Но должен быть заполнен
			ТекстОшибки = НСтр("ru = 'Адрес не заполнен.'");
			СписокОшибок.Добавить(ПоляОшибки(ТекстОшибки, Ложь));
		КонецЕсли;
		
		Возврат СписокОшибок;
	КонецЕсли;
	
	ВсеОшибки = ОбщиеГруппыОшибокЗаполненияАдреса(Адрес, ФлагиПроверки);
	
	Если ВсеОшибки.Количество() > 0 Тогда
		Для Каждого Группа Из ВсеОшибки Цикл
			Для Каждого Поле Из Группа.Поля Цикл
				СписокОшибок.Добавить(ПоляОшибки( Поле.Сообщение, Истина, Поле.ИмяПоля));
			КонецЦикла;
		КонецЦикла;
		Возврат СписокОшибок;
	КонецЕсли;
	
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.АдресныйКлассификатор") Тогда
		
		ОшибкиКлассификатора = Новый СписокЗначений;
		ЗаполнитьОшибкиАдресаПоКлассификатору(Адрес, ФлагиПроверки, ОшибкиКлассификатора);
		Для Каждого ЭлементСписка Из ОшибкиКлассификатора Цикл
			ДанныеОшибки = ЭлементСписка.Значение; // см. ОписаниеОшибкиПроверки
			СписокОшибок.Добавить(ПоляОшибки(ЭлементСписка.Представление, ДанныеОшибки.АдресПроверен, ДанныеОшибки.ПутьXPath, ДанныеОшибки.Варианты));
		КонецЦикла;
		
	КонецЕсли;
	
	Возврат СписокОшибок;
КонецФункции

Функция ПоляОшибки(ТекстОшибки, АдресПроверен, ИмяПоля = "Представление", ВариантАдреса = Неопределено)
	
	Если ВариантАдреса = Неопределено Тогда
		ВариантАдреса = Новый Массив;
	КонецЕсли;
	
	Результат = Новый Структура;
	Результат.Вставить("ТекстОшибки",   ТекстОшибки);
	Результат.Вставить("АдресПроверен", АдресПроверен);
	Результат.Вставить("ИмяПоля",       ИмяПоля);
	Результат.Вставить("ВариантАдреса", ВариантАдреса);
	
	Возврат Результат;
	
КонецФункции

Процедура ТолькоЛатиницаВСтроке(Значение, Знач Результат)
	
	Если Не СтроковыеФункцииКлиентСервер.ТолькоЛатиницаВСтроке(Значение, Ложь, "1234567890,") Тогда
		ТекстОшибки = НСтр("ru = 'Адрес в международном формате должен быть набран латиницей.'");
		Результат.Добавить(ПоляОшибки(ТекстОшибки, Истина));
	КонецЕсли;

КонецПроцедуры

// Общие проверки на корректность адреса.
//
//  Параметры:
//      ДанныеАдреса  - Строка
//                    - СписокЗначений - XML, XDTO с данными адреса РФ.
//      ВидИнформации - СправочникСсылка.ВидыКонтактнойИнформации - ссылка на соответствующий вид контактной информации.
//
// Возвращаемое значение:
//      Массив - содержит структуры с полями:
//         * ТипОшибки - Строка - идентификатор группы ошибки. Может принимать значение
//              "ПредставлениеНеСоответствуетНаборуПолей",
//              "НеЗаполненыОбязательныеПоля"
//              "НеУказаныСокращенияПолей"
//              "НедопустимыеСимволыПолей"
//              "НеСоответствуетДлинаПолей".
//         * Сообщение - Строка - подробный текст ошибки.
//         * Поля - Массив из Структура:
//             ** ИмяПоля - Строка - внутренний идентификатор ошибочного поля.
//             ** Сообщение - Строка- подробный текст ошибки для поля.
//
Функция ОбщиеГруппыОшибокЗаполненияАдреса(Знач ДанныеАдреса, Знач ВидИнформации)
	Результат = Новый Массив;
	
	НеЗаполненыОбязательныеПоля = ГруппаОшибокАдреса("НеЗаполненыОбязательныеПоля",
		НСтр("ru = 'Не заполнены обязательные поля:'"));
	Результат.Добавить(НеЗаполненыОбязательныеПоля);
	
	НеУказаныСокращенияПолей = ГруппаОшибокАдреса("НеУказаныСокращенияПолей",
		НСтр("ru = 'Не указано сокращение для полей:'"));
	Результат.Добавить(НеУказаныСокращенияПолей);
	
	НедопустимыеСимволыПолей = ГруппаОшибокАдреса("НедопустимыеСимволыПолей",
		НСтр("ru = 'Найдены недопустимые символы в полях:'"));
	Результат.Добавить(НедопустимыеСимволыПолей);
	
	НеСоответствуетДлинаПолей = ГруппаОшибокАдреса("НеСоответствуетДлинаПолей",
		НСтр("ru = 'Не соответствует установленной длина полей:'"));
	Результат.Добавить(НеСоответствуетДлинаПолей);
	
	Регион = УправлениеКонтактнойИнформациейКлиентСервер.СоединитьНаименованиеИТипАдресногоОбъекта(ДанныеАдреса.Area,
		ДанныеАдреса.AreaType, Истина);
		
	Если ПустаяСтрока(Регион) Тогда
		ДобавитьОшибкуЗаполненияАдреса(НеЗаполненыОбязательныеПоля, "СубъектРФ",
			НСтр("ru = 'Не указан регион адреса'"), "Регион");
	КонецЕсли;
		
	// 3) Регион, Район, Город, НаселенныйПункт, Улица должны:
	//      - иметь сокращение.
	//      - не длинней 50 символов.
	//      - только кириллица.
	
	ДопустимоКромеКириллицы = "/,-. 0123456789_NIV";
	
	// Регион
	Если Не ПустаяСтрока(Регион) Тогда
		Поле = "СубъектРФ";
		Если ПустаяСтрока(ДанныеАдреса.AreaType) Тогда
			ДобавитьОшибкуЗаполненияАдреса(НеУказаныСокращенияПолей, "СубъектРФ",
				СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Для региона ""%1"" не указан тип (республика, область, город и пр.)'"), Регион), НСтр("ru = 'Регион'"));
		КонецЕсли;
		Если Не СтроковыеФункцииКлиентСерверРФ.ТолькоКириллицаВСтроке(Регион, Ложь, ДопустимоКромеКириллицы) Тогда
			ДобавитьОшибкуЗаполненияАдреса(НедопустимыеСимволыПолей, Поле,
				СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'В названии региона ""%1"" есть не кириллические символы'"), Регион), НСтр("ru = 'Регион'"));
		КонецЕсли
	КонецЕсли;
	
	// Район
	Район = УправлениеКонтактнойИнформациейКлиентСервер.СоединитьНаименованиеИТипАдресногоОбъекта(ДанныеАдреса.District, ДанныеАдреса.DistrictType);
	Если Не ПустаяСтрока(Район) Тогда
		Поле = "Район";
		Если ПустаяСтрока(ДанныеАдреса.DistrictType) Тогда
			ДобавитьОшибкуЗаполненияАдреса(НеУказаныСокращенияПолей, Поле,
				СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Для района ""%1"" не указан тип (район, поселение и пр.)'"), Район), НСтр("ru = 'Район'"));
		КонецЕсли;
		Если Не СтроковыеФункцииКлиентСерверРФ.ТолькоКириллицаВСтроке(Район, Ложь, ДопустимоКромеКириллицы) Тогда
			ДобавитьОшибкуЗаполненияАдреса(НедопустимыеСимволыПолей, Поле,
				СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'В названии района ""%1"" есть не кириллические символы'"), Район), НСтр("ru = 'Район'"));
		КонецЕсли;
	КонецЕсли;
	
	// Город
	Город = УправлениеКонтактнойИнформациейКлиентСервер.СоединитьНаименованиеИТипАдресногоОбъекта(ДанныеАдреса.City, ДанныеАдреса.CityType);
	Если Не ПустаяСтрока(Город) Тогда
		Поле = "Город";
		Если ПустаяСтрока(ДанныеАдреса.CityType) Тогда
			ДобавитьОшибкуЗаполненияАдреса(НеУказаныСокращенияПолей, Поле,
				СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Для города ""%1"" не указан тип (город, поселок, сельское поселение и пр.)'"), Город), НСтр("ru = 'Город'"));
		КонецЕсли;
		Если Не СтроковыеФункцииКлиентСерверРФ.ТолькоКириллицаВСтроке(Город, Ложь, ДопустимоКромеКириллицы) Тогда
			ДобавитьОшибкуЗаполненияАдреса(НедопустимыеСимволыПолей, Поле,
				СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'В названии города ""%1"" есть не кириллические символы'"), Город), НСтр("ru = 'Город'"));
		КонецЕсли;
	КонецЕсли;
	
	// Населенный пункт
	НаселенныйПункт = УправлениеКонтактнойИнформациейКлиентСервер.СоединитьНаименованиеИТипАдресногоОбъекта(ДанныеАдреса.Locality, ДанныеАдреса.LocalityType);
	Если Не ПустаяСтрока(НаселенныйПункт) Тогда
		Поле = "НаселПункт";
		Если ПустаяСтрока(ДанныеАдреса.LocalityType) Тогда
			ДобавитьОшибкуЗаполненияАдреса(НеУказаныСокращенияПолей, Поле,
				СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Для населенного пункта ""%1"" не указан тип (город, деревня, село и пр.)'"), НаселенныйПункт),
					НСтр("ru = 'Населенный пункт'"));
		КонецЕсли;
		Если Не СтроковыеФункцииКлиентСерверРФ.ТолькоКириллицаВСтроке(НаселенныйПункт, Ложь, ДопустимоКромеКириллицы) Тогда
			ДобавитьОшибкуЗаполненияАдреса(НедопустимыеСимволыПолей, Поле,
				СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'В названии населенного пункта ""%1"" есть не кириллические символы'"), НаселенныйПункт),
					НСтр("ru = 'Населенный пункт'"));
		КонецЕсли;
	КонецЕсли;
	
	// Улица
	Улица = УправлениеКонтактнойИнформациейКлиентСервер.СоединитьНаименованиеИТипАдресногоОбъекта(ДанныеАдреса.Street, ДанныеАдреса.StreetType);
	Если Не ПустаяСтрока(Улица) Тогда
		Поле = "Улица";
		Если ПустаяСтрока(ДанныеАдреса.StreetType) Тогда
			ДобавитьОшибкуЗаполненияАдреса(НеУказаныСокращенияПолей, Поле,
				СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Для улицы ""%1"" не указан тип (улица, переулок, шоссе и пр.)'"), Улица), НСтр("ru = 'Улица'"));
		КонецЕсли;
		Если Не СтроковыеФункцииКлиентСерверРФ.ТолькоКириллицаВСтроке(Улица, Ложь, ДопустимоКромеКириллицы) Тогда
			ДобавитьОшибкуЗаполненияАдреса(НедопустимыеСимволыПолей, Поле,
				СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'В названии улицы ""%1"" есть не кириллические символы'"), Улица), НСтр("ru = 'Улица'"));
		КонецЕсли;
	КонецЕсли;
	
	// 4) Индекс - если есть, то 6 цифр.
	Если Не ПустаяСтрока(ДанныеАдреса.ZipCode) Тогда
		Поле = "Индекс";
		Если СтрДлина(ДанныеАдреса.ZipCode) <> 6 Или Не СтроковыеФункцииКлиентСервер.ТолькоЦифрыВСтроке(ДанныеАдреса.ZipCode) Тогда
			ДобавитьОшибкуЗаполненияАдреса(НеСоответствуетДлинаПолей, Поле,
				НСтр("ru = 'Почтовый индекс должен состоять из 6 цифр'"),
				НСтр("ru = 'Индекс'"));
		КонецЕсли;
	КонецЕсли;
	
	// 6) Поля Город и НаселенныйПункт могут быть одновременно пустые только в регионе - городе ФЗ.
	Территория = УправлениеКонтактнойИнформациейКлиентСервер.СоединитьНаименованиеИТипАдресногоОбъекта(ДанныеАдреса.territory, ДанныеАдреса.territoryType);
	Если ПустаяСтрока(Город) И ПустаяСтрока(НаселенныйПункт) И ПустаяСтрока(Территория) И ПустаяСтрока(Район) Тогда
		Если РаботаСАдресами.ЭтоГородФедеральногоЗначения(Регион) = Ложь Тогда
			ДобавитьОшибкуЗаполненияАдреса(НеЗаполненыОбязательныеПоля, "Город",
				НСтр("ru = 'Город может быть не указан только в регионе - городе федерального значения'"),
				НСтр("ru = 'Город'"));
			ДобавитьОшибкуЗаполненияАдреса(НеЗаполненыОбязательныеПоля, "НаселПункт",
				НСтр("ru = 'Населенный пункт может быть не указан только в регионе - городе федерального значения'"),
				НСтр("ru = 'Населенный пункт'"));
		КонецЕсли;
	КонецЕсли;
	
	// 7) Дома не могут быть пустыми
	Если ПустаяСтрока(ДанныеАдреса.houseNumber) И ДанныеАдреса.buildings.Количество() = 0 И ПустаяСтрока(ДанныеАдреса.stead) Тогда
		Поле = "Дом";
		ДобавитьОшибкуЗаполненияАдреса(НеСоответствуетДлинаПолей, Поле,
			НСтр("ru = 'Не указан номер дома'"),
			НСтр("ru = 'Дом'"));
	КонецЕсли;
	
	// Все. Убираем пустые результаты, корректируем сообщение группы.
	Для Индекс = 1-Результат.Количество() По 0 Цикл
		Группа = Результат[-Индекс];
		Поля = Группа.Поля;
		СписокСущностей = "";
		Для ИндексПоля = 1-Поля.Количество() По 0 Цикл
			Поле = Поля[-ИндексПоля];
			Если ПустаяСтрока(Поле.Сообщение) Тогда
				Поля.Удалить(-ИндексПоля);
			Иначе
				СписокСущностей = ", " + Поле.СущностьПоля + СписокСущностей;
				Поле.Удалить("СущностьПоля");
			КонецЕсли;
		КонецЦикла;
		Если Поля.Количество() = 0 Тогда
			Результат.Удалить(-Индекс);
		ИначеЕсли Не ПустаяСтрока(СписокСущностей) Тогда
			Группа.Сообщение = Группа.Сообщение + Сред(СписокСущностей, 2);
		КонецЕсли;
	КонецЦикла;
	
	Возврат Результат;
КонецФункции

Функция ГруппаОшибокАдреса(ТипОшибки, Сообщение)
	Возврат Новый Структура("ТипОшибки, Сообщение, Поля", ТипОшибки, Сообщение, Новый Массив);
КонецФункции

Процедура ДобавитьОшибкуЗаполненияАдреса(Группа, ИмяПоля = "", Сообщение = "", СущностьПоля = "")
	Группа.Поля.Добавить(Новый Структура("ИмяПоля, Сообщение, СущностьПоля", ИмяПоля, Сообщение, СущностьПоля));
КонецПроцедуры

Процедура ЗаполнитьОшибкиАдресаПоКлассификатору(АдресРФ, ФлагиПроверки, Результат)
	
	Адрес = Новый Массив;
	Адрес.Добавить(Новый Структура("Адрес, ФорматАдреса", АдресРФ, "ФИАС"));
	
	МодульАдресныйКлассификаторСлужебный = ОбщегоНазначения.ОбщийМодуль("АдресныйКлассификаторСлужебный");
	РезультатыАнализа = МодульАдресныйКлассификаторСлужебный.РезультатПроверкиАдресовПоКлассификатору(Адрес);
	Если РезультатыАнализа.Отказ Тогда
		ОписаниеОшибкиПроверки = ОписаниеОшибкиПроверки();
		ОписаниеОшибкиПроверки.ПутьXPath = "/";
		Результат.Добавить(ОписаниеОшибкиПроверки, РезультатыАнализа.КраткоеПредставлениеОшибки);
		Возврат;
	КонецЕсли;
	
	// Только уникальные ошибки - мы могли проверить адрес два раза.
	Обработанные = Новый Соответствие;
	Для Каждого РезультатПроверки Из РезультатыАнализа.Данные Цикл
			Для Каждого ОшибкаАдреса Из РезультатПроверки.Ошибки Цикл
				Ключ = ОшибкаАдреса.Ключ;
				Если Обработанные[Ключ] = Неопределено Тогда
					
					ОписаниеОшибкиПроверки = ОписаниеОшибкиПроверки();
					ОписаниеОшибкиПроверки.ПутьXPath     = Ключ;
					ОписаниеОшибкиПроверки.СущностьПоля  = Неопределено;
					ОписаниеОшибкиПроверки.АдресПроверен = РезультатПроверки.АдресПроверен;
					ОписаниеОшибкиПроверки.Варианты      = РезультатПроверки.Варианты;
					
					Результат.Добавить(ОписаниеОшибкиПроверки, СокрЛП(ОшибкаАдреса.Текст + Символы.ПС + ОшибкаАдреса.Подсказка));
					Обработанные[Ключ] = Истина;
				КонецЕсли;
			КонецЦикла;
	КонецЦикла;
	
КонецПроцедуры

// Возвращаемое значение:
//   Структура:
//   * Варианты - Массив
//   * АдресПроверен - Булево
//   * СущностьПоля - Неопределено
//   * ПутьXPath - Строка
//
Функция ОписаниеОшибкиПроверки()
	 
		ОписаниеОшибки = Новый Структура;
		ОписаниеОшибки.Вставить("ПутьXPath",     "");
		ОписаниеОшибки.Вставить("СущностьПоля",  Неопределено);
		ОписаниеОшибки.Вставить("АдресПроверен", Ложь);
		ОписаниеОшибки.Вставить("Варианты",      Новый Массив);
		Возврат ОписаниеОшибки;
		
КонецФункции

Функция СтруктураОшибкиПоставщикаАдресногоКлассификатора(ИсходнаяСтруктура = Неопределено)
	
	Если ИсходнаяСтруктура = Неопределено Тогда
		ИсходнаяСтруктура = Новый Структура;
	КонецЕсли;
		
	ИсходнаяСтруктура.Вставить("Отказ", Ложь);
	ИсходнаяСтруктура.Вставить("ПодробноеПредставлениеОшибки");
	ИсходнаяСтруктура.Вставить("КраткоеПредставлениеОшибки");

	Возврат ИсходнаяСтруктура;
КонецФункции

// Параметры:
//  Адрес - Строка
//  СтрокаТабличнойЧасти - СтрокаТаблицыЗначений из см. Справочник.Пользователи.КонтактнаяИнформация
// 
Процедура ЗаполнитьРасширенныеРеквизитыТабличнойЧастиДляАдреса(Знач Адрес, Знач СтрокаТабличнойЧасти) Экспорт
	
	Если УправлениеКонтактнойИнформациейСлужебный.ЭтоНациональныйАдрес(Адрес) Тогда
		// национальный адрес
		СтрокаТабличнойЧасти.Регион = Строка(Адрес.Area) + ?(ПустаяСтрока(Адрес.AreaType), "", " " + Адрес.AreaType);
		СтрокаТабличнойЧасти.Город  = Строка(Адрес.City) + ?(ПустаяСтрока(Адрес.CityType), "", " " + Адрес.CityType);
	КонецЕсли;

КонецПроцедуры

// Возвращает список значение содержащий номера земельных участков для автоподбора.
//
//  Параметры:
//      ИдентификаторАдресногоОбъекта         - УникальныйИдентификатор - населенный пункт или улица.
//      СтрокаПоиска                   - Строка - текст автоподбора.
// Возвращаемое значение:
//       СписокЗначений - результат для автоподбора.
//
Функция СписокАвтоподбораЗемельныхУчастков(ИдентификаторАдресногоОбъекта, СтрокаПоиска) Экспорт
	
	ВариантыУчастков = Новый СписокЗначений;
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.АдресныйКлассификатор") Тогда
		МодульАдресныйКлассификаторСлужебный = ОбщегоНазначения.ОбщийМодуль("АдресныйКлассификаторСлужебный");
		СписокУчастков = МодульАдресныйКлассификаторСлужебный.СписокЗемельныхУчастков(ИдентификаторАдресногоОбъекта, СтрокаПоиска);
	КонецЕсли;
	
	ВариантыУчастков = Новый СписокЗначений;
	Если СписокУчастков <> Неопределено Тогда
		Для каждого Строка Из СписокУчастков Цикл
			ВариантыУчастков.Добавить(Строка.Значение, Строка.Представление);
		КонецЦикла;
	КонецЕсли;
	
	Возврат ВариантыУчастков;
КонецФункции

// Возвращает список земельных участков по идентификатору адресного объекта, поиск по подобию.
//
// Параметры:
//     ИдентификаторАдресногоОбъекта - УникальныйИдентификатор - родительский объект.
//     СтрокаПоиска                  - Строка                  - текст, отбора в списке домов.
//
// Возвращаемое значение:
//     ТаблицаЗначений  -  найденные варианты.
//
Функция СписокЗемельныхУчастков(ИдентификаторАдресногоОбъекта, СтрокаПоиска = "", ПорцияПриПоиске = 20) Экспорт
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.АдресныйКлассификатор") Тогда
		МодульАдресныйКлассификаторСлужебный = ОбщегоНазначения.ОбщийМодуль("АдресныйКлассификаторСлужебный");
		ЗемельныеУчастки = МодульАдресныйКлассификаторСлужебный.СписокЗемельныхУчастков(ИдентификаторАдресногоОбъекта, СтрокаПоиска, ПорцияПриПоиске);
		
		Возврат ЗемельныеУчастки;
	КонецЕсли;
	
	Возврат Неопределено;
	
КонецФункции

//======================================================================================================================
// Обратная совместимость

// Возвращает поля контактной информации.
//
// Параметры:
//   XDTOКонтактнаяИнформация - ОбъектXDTO
//                            - Строка - контактная информация или строка XML.
//   СтарыйСоставПолей        - Булево - флаг того, что из состава полей будут исключены
//                                          поля, отсутствующие в версиях БСП младше 2.1.3.
//
// Возвращаемое значение:
//   Структура:
//     * Представление        - Строка - представление адреса.
//     * ЗначенияПолей        - СписокЗначений - значения. Состав значений для адреса:
//        ** Страна           - Строка - текстовое представление страны.
//        ** КодСтраны        - Строка - код страны по ОКСМ.
//        ** Индекс           - Строка - почтовый индекс (только для адресов РФ).
//        ** Регион           - Строка - текстовое представление региона РФ (только для адресов РФ).
//        ** КодРегиона       - Строка - код региона РФ (только для адресов РФ).
//        ** РегионСокращение - Строка - сокращение региона (если СтарыйСоставПолей = Ложь).
//        ** Район            - Строка - текстовое представление района (только для адресов РФ).
//        ** РайонСокращение  - Строка - сокращение района (если СтарыйСоставПолей = Ложь).
//        ** Город            - Строка - текстовое представление города (только для адресов РФ).
//        ** ГородСокращение  - Строка - сокращение города (только для адресов РФ).
//        ** НаселенныйПункт  - Строка - текстовое представление населенного пункта (только для адресов РФ).
//        ** НаселенныйПунктСокращение - сокращение населенного пункта (если СтарыйСоставПолей = Ложь).
//        ** ТипДома          - см. РаботаСАдресами.ТипыОбъектовАдресацииАдресаРФ.
//        ** Дом              - Строка - текстовое представление дома (только для адресов РФ).
//        ** ТипКорпуса       - см. РаботаСАдресами.ТипыОбъектовАдресацииАдресаРФ.
//        ** Корпус           - Строка - текстовое представление корпуса (только для адресов РФ).
//        ** ТипКвартиры      - см. РаботаСАдресами.ТипыОбъектовАдресацииАдресаРФ.
//        ** Квартира         - Строка - текстовое представление квартиры (только для адресов РФ).
//       Состав значений для телефона:
//        ** КодСтраны        - Строка - код страны. Например, +7.
//        ** КодГорода        - Строка - код города. Например, 495.
//        ** НомерТелефона    - Строка - номер телефона.
//        ** Добавочный       - Строка - добавочный номер телефона.
//
Функция КонтактнаяИнформацияВСтаруюСтруктуру(XDTOКонтактнаяИнформация, СтарыйСоставПолей = Ложь) Экспорт
	
	Если УправлениеКонтактнойИнформациейКлиентСервер.ЭтоКонтактнаяИнформацияВXML(XDTOКонтактнаяИнформация) Тогда
		XDTOКонтактная = УправлениеКонтактнойИнформациейЛокализация.КонтактнаяИнформацияИзXML(XDTOКонтактнаяИнформация);
	Иначе
		XDTOКонтактная = XDTOКонтактнаяИнформация
	КонецЕсли;
	
	Результат = Новый Структура("Представление, ЗначенияПолей", XDTOКонтактная.Представление, Новый СписокЗначений);
	
	ПространствоИмен = УправлениеКонтактнойИнформациейЛокализация.ПространствоИмен();
	Состав = XDTOКонтактная.Состав;
	
	Если Состав = Неопределено Тогда
		Возврат Результат;
	КонецЕсли;
	
	Тип = Состав.Тип();
	Если Тип = ФабрикаXDTO.Тип(ПространствоИмен, "Адрес") Тогда
		Результат.ЗначенияПолей = АдресВСтарыйСписокПолей(Состав, Не СтарыйСоставПолей);
		Результат.ЗначенияПолей.Добавить(Результат.Представление, "Представление");
		
	ИначеЕсли Тип = ФабрикаXDTO.Тип(ПространствоИмен, "НомерТелефона") Тогда
		Результат.ЗначенияПолей = УправлениеКонтактнойИнформациейЛокализация.НомерТелефонаВСтарыйСписокПолей(Состав);
		Результат.ЗначенияПолей.Добавить(XDTOКонтактная.Комментарий, "Комментарий");
	КонецЕсли;
	
	Возврат Результат;
КонецФункции

// Преобразует адрес формата XDTO в старый список полей типа СписокЗначений.
//
// Параметры:
//     XDTOАдрес               - ОбъектXDTO
//                             - Строка - контактная информация или строка XML.
//     РасширенныйСоставПолей - Булево - флаг того, что состав полей будет сокращен для совместимости
//                                     с обменом БСП 2.1.2.
//
//  Возвращаемое значение:
//     СписокЗначений
//
Функция АдресВСтарыйСписокПолей(XDTOАдрес, РасширенныйСоставПолей = Истина)
	Список = Новый СписокЗначений;
	
	ПространствоИмен = УправлениеКонтактнойИнформациейЛокализация.ПространствоИмен();
	XDTOТип = XDTOАдрес.Тип();
	Если XDTOТип = ФабрикаXDTO.Тип(ПространствоИмен, "Адрес") Тогда
		
		// Страна с кодом
		ДобавитьЗначение(Список, "Страна", XDTOАдрес.Страна);
		Если ПустаяСтрока(XDTOАдрес.Страна) Тогда
			КодСтраны = "";
		Иначе
			Страна = Справочники.СтраныМира.НайтиПоНаименованию(XDTOАдрес.Страна, Истина);
			КодСтраны = СокрЛП(Страна.Код);
		КонецЕсли;
		ДобавитьЗначение(Список, "КодСтраны", КодСтраны);
		
		Если Не РаботаСАдресамиКлиентСервер.ЭтоОсновнаяСтрана(XDTOАдрес.Страна) Тогда
			Возврат Список;
		КонецЕсли;
		
		АдресРФ = XDTOАдрес.Состав;
		
	ИначеЕсли XDTOТип = ФабрикаXDTO.Тип(РаботаСАдресами.ПространствоИмен(), "АдресРФ") Тогда
		АдресРФ = XDTOАдрес;
		
	Иначе
		Возврат Список;
		
	КонецЕсли;
	
	ДобавитьЗначение(Список, "Индекс", ПочтовыйИндексАдреса(АдресРФ) );
	
	ДобавитьЗначение(Список, "Регион", АдресРФ.СубъектРФ);
	ДобавитьЗначение(Список, "КодРегиона", РаботаСАдресами.КодРегиона(АдресРФ.СубъектРФ) );
	Если РасширенныйСоставПолей Тогда
		ДобавитьЗначение(Список, "РегионСокращение", Сокращение(АдресРФ.СубъектРФ));
	КонецЕсли;
	
	Район = РайонАдреса(АдресРФ);
	ДобавитьЗначение(Список, "Район", Район);
	Если РасширенныйСоставПолей Тогда
		ДобавитьЗначение(Список, "РайонСокращение", Сокращение(Район));
	КонецЕсли;
	
	ДобавитьЗначение(Список, "Город", АдресРФ.Город);
	Если РасширенныйСоставПолей Тогда
		ДобавитьЗначение(Список, "ГородСокращение", Сокращение(АдресРФ.Город));
	КонецЕсли;
	
	// преобразование в КЛАДР
	НаселенныйПункт                 = АдресРФ.НаселПункт;
	Улица                           = АдресРФ.Улица;
	ДополнительныйЭлементАдреса     = НайтиДополнительныйЭлементАдреса(АдресРФ).Значение;
	ПодчиненныйЭлементЭлементАдреса = ДополнительныйЭлементАдреса(АдресРФ,
		РаботаСАдресами.XPathДополнительногоОбъектаАдресации(91));
	
	ЕстьДополнительныйЭлементАдреса     = ЗначениеЗаполнено(ДополнительныйЭлементАдреса);
	ЕстьПодчиненныйЭлементЭлементАдреса = ЗначениеЗаполнено(ПодчиненныйЭлементЭлементАдреса);
	
	Если ЕстьДополнительныйЭлементАдреса Тогда
		
		Если ЕстьПодчиненныйЭлементЭлементАдреса Тогда
			НаселенныйПункт = ДополнительныйЭлементАдреса;
			Улица = ПодчиненныйЭлементЭлементАдреса;
		Иначе
			Улица = ДополнительныйЭлементАдреса;
		КонецЕсли;
		
	ИначеЕсли ЕстьПодчиненныйЭлементЭлементАдреса Тогда
		Улица = ПодчиненныйЭлементЭлементАдреса;
	КонецЕсли;
	
	ДобавитьЗначение(Список, "НаселенныйПункт", НаселенныйПункт);
	Если РасширенныйСоставПолей Тогда
		ДобавитьЗначение(Список, "НаселенныйПунктСокращение", Сокращение(НаселенныйПункт));
	КонецЕсли;

	ДобавитьЗначение(Список, "Улица", Улица);
	
	Если РасширенныйСоставПолей Тогда
		ДобавитьЗначение(Список, "УлицаСокращение", Сокращение(Улица));
	КонецЕсли;
	
	// Дом и корпус
	ЗданияИПомещения = ЗданияИПомещенияАдреса(АдресРФ);
	
	Если ЗданияИПомещения.Здания.Количество() = 0 Тогда
		ДобавитьЗначение(Список, "ТипДома", "");
		ДобавитьЗначение(Список, "Дом",     "");
	Иначе
		СтрокаОбъекта = ЗданияИПомещения.Здания[0];
		ДобавитьЗначение(Список, "ТипДома", СтрокаОбъекта.Тип,      Ложь);
		ДобавитьЗначение(Список, "Дом",     СтрокаОбъекта.Значение, Ложь);
		
		ЗданияИПомещения.Удалить(СтрокаОбъекта);
		Если ЗданияИПомещения.Здания.Количество() > 0 Тогда
			
			ПараметрыОбъекта = ЗначениеЗданияИлиПомещения(ЗданияИПомещения.Здания, РаботаСАдресамиПовтИсп.ВариантыДанныхСтроение(), Ложь);
			Если ПараметрыОбъекта.Количество() = 0 Тогда
				ДобавитьЗначение(Список, "ТипКорпуса", "");
				ДобавитьЗначение(Список, "Корпус",     "");
			ИначеЕсли ПараметрыОбъекта.Количество() = 1 Тогда
				СтрокаОбъекта  = ПараметрыОбъекта[0];
				ДобавитьЗначение(Список, "ТипКорпуса", СтрокаОбъекта.Тип,      Ложь);
				ДобавитьЗначение(Список, "Корпус",     СтрокаОбъекта.Значение, Ложь);
			Иначе
				ТипКорпуса  = ПараметрыОбъекта[0].Тип;
				ЗначениеКорпуса = "";
				Разделитель = "";
				Сокращения = РаботаСАдресами.СокращенияОбъектовАдресацииАдресаРФ();
				Для Каждого СтрокаОбъекта Из ПараметрыОбъекта Цикл
					ИмяЗдания = ?(ЗначениеЗаполнено(Сокращения[СтрокаОбъекта.Тип]), Сокращения[СтрокаОбъекта.Тип], СтрокаОбъекта.Тип);
					ЗначениеКорпуса  = ЗначениеКорпуса  + Разделитель + ИмяЗдания + " " + СтрокаОбъекта.Значение;
					Разделитель = ", " ;
				КонецЦикла;
				ДобавитьЗначение(Список, "ТипКорпуса", ТипКорпуса,      РасширенныйСоставПолей);
				ДобавитьЗначение(Список, "Корпус",     ЗначениеКорпуса  , РасширенныйСоставПолей);
			КонецЕсли;
		КонецЕсли;
		
	КонецЕсли;
	
	ПараметрыОбъекта = ЗначениеЗданияИлиПомещения(ЗданияИПомещения.Помещения, РаботаСАдресамиПовтИсп.ВариантыДанныхПомещение(), РасширенныйСоставПолей);
	Если ПараметрыОбъекта.Количество() = 0 Тогда
		ДобавитьЗначение(Список, "ТипКвартиры", "");
		ДобавитьЗначение(Список, "Квартира",    "");
	ИначеЕсли ПараметрыОбъекта.Количество() = 1 Тогда
		СтрокаОбъекта  = ПараметрыОбъекта[0];
		ДобавитьЗначение(Список, "ТипКвартиры", СтрокаОбъекта.Тип,      РасширенныйСоставПолей);
		ДобавитьЗначение(Список, "Квартира",    СтрокаОбъекта.Значение, РасширенныйСоставПолей);
	Иначе
		ТипПомещения  = ПараметрыОбъекта[0].Тип;
		ЗначениеПомещения = "";
		Разделитель = "";
		Сокращения = РаботаСАдресами.СокращенияОбъектовАдресацииАдресаРФ();
		Для Каждого СтрокаОбъекта Из ПараметрыОбъекта Цикл
			ИмяПомещения = ?(ЗначениеЗаполнено(Сокращения[СтрокаОбъекта.Тип]), Сокращения[СтрокаОбъекта.Тип], СтрокаОбъекта.Тип);
			ЗначениеПомещения = ЗначениеПомещения + Разделитель + ИмяПомещения + " " + СтрокаОбъекта.Значение;
			Разделитель = ", " ;
		КонецЦикла;
		ДобавитьЗначение(Список, "ТипКвартиры", ТипПомещения,      РасширенныйСоставПолей);
		ДобавитьЗначение(Список, "Квартира",    ЗначениеПомещения, РасширенныйСоставПолей);
	КонецЕсли;
	
	Возврат Список;
КонецФункции

Процедура ДобавитьЗначение(Список, ИмяПоля, Значение, РазрешитьДубли = Ложь)
	
	Если Не РазрешитьДубли Тогда
		Для Каждого Элемент Из Список Цикл
			Если Элемент.Представление = ИмяПоля Тогда
				Элемент.Значение = Строка(Значение);
				Возврат;
			КонецЕсли;
		КонецЦикла;
	КонецЕсли;
	
	Список.Добавить(Строка(Значение), ИмяПоля);
КонецПроцедуры

// Возвращает отдельно сокращение от значения.
//
// Параметры:
//     Текст - Строка - полное наименования.
//
// Возвращаемое значение:
//     Строка - выделенное сокращение.
//
Функция Сокращение(Знач Текст)
	
	Части = УправлениеКонтактнойИнформациейКлиентСервер.НаименованиеСокращение(Текст);
	Возврат Части.Сокращение;
	
КонецФункции

// Возвращает варианты типов домов (по признаку владения).
Функция ВариантыДанныхДом() Экспорт
	
	Результат = Новый Структура("ВариантыТипа, МожноПодбиратьЗначения", Новый Массив, Ложь);
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.АдресныйКлассификатор") Тогда
		МодульАдресныйКлассификаторПовтИсп = ОбщегоНазначения.ОбщийМодуль("АдресныйКлассификаторПовтИсп");
		ВладенияИСтроения = МодульАдресныйКлассификаторПовтИсп.НаименованияВладенийИСтроений();
		
		Для каждого КлючИЗначение Из ВладенияИСтроения.Владения Цикл
			Результат.ВариантыТипа.Добавить(КлючИЗначение.Значение);
		КонецЦикла;
		
	КонецЕсли;
	
	ДополнительныеВариантыТипов = РаботаСАдресами.НаименованияОбъектовАдресацииПоТипу(1, Ложь);
	ОбщегоНазначенияКлиентСервер.ДополнитьМассив(Результат.ВариантыТипа, ДополнительныеВариантыТипов);
	
	Позиция = Результат.ВариантыТипа.Найти(ДополнительныеВариантыТипов.Получить(0));
	Если Позиция <> Неопределено И Позиция > 0 Тогда
		ЗаписьОДоме = Результат.ВариантыТипа.Получить(Позиция);
		Результат.ВариантыТипа.Удалить(Позиция);
		Результат.ВариантыТипа.Вставить(0, ЗаписьОДоме);
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

// Возвращает варианты типов домов (по признаку строения).
Функция ВариантыДанныхСтроение() Экспорт
	
	Результат = Новый Структура("ВариантыТипа, МожноПодбиратьЗначения", Новый Массив, Ложь);
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.АдресныйКлассификатор") Тогда
		МодульАдресныйКлассификаторПовтИсп = ОбщегоНазначения.ОбщийМодуль("АдресныйКлассификаторПовтИсп");
		ВладенияИСтроения = МодульАдресныйКлассификаторПовтИсп.НаименованияВладенийИСтроений();
		
		Для каждого КлючИЗначение Из ВладенияИСтроения.Строения Цикл
			Результат.ВариантыТипа.Добавить(КлючИЗначение.Значение);
		КонецЦикла;
		
	КонецЕсли;
	
	ДополнительныеВариантыТипов = РаботаСАдресами.НаименованияОбъектовАдресацииПоТипу(2, Ложь);
	ОбщегоНазначенияКлиентСервер.ДополнитьМассив(Результат.ВариантыТипа, ДополнительныеВариантыТипов);
	
	Возврат Результат;
		
КонецФункции

// Возвращает варианты типов помещений.
Функция ВариантыДанныхПомещение() Экспорт
	
	Результат = Новый Структура("ВариантыТипа, МожноПодбиратьЗначения", Новый Массив, Ложь);
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.АдресныйКлассификатор") Тогда
		МодульАдресныйКлассификаторПовтИсп = ОбщегоНазначения.ОбщийМодуль("АдресныйКлассификаторПовтИсп");
		Помещения = МодульАдресныйКлассификаторПовтИсп.НаименованияПомещений();
		
		Для каждого КлючИЗначение Из Помещения Цикл
			Результат.ВариантыТипа.Добавить(КлючИЗначение.Значение);
		КонецЦикла;
		
	КонецЕсли;
	
	ДополнительныеВариантыТипов = РаботаСАдресами.НаименованияОбъектовАдресацииПоТипу(3, Ложь);
	ОбщегоНазначенияКлиентСервер.ДополнитьМассив(Результат.ВариантыТипа, ДополнительныеВариантыТипов);
	
	
	Возврат Результат;
		
КонецФункции

#КонецОбласти

#КонецЕсли